package com.todo.member.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.component.redis.RedisService;
import com.todo.member.application.convert.MemberInfoConvert;
import com.todo.member.application.entity.bo.MemberLevelBO;
import com.todo.member.application.entity.condition.MemberLevelConditionBO;
import com.todo.member.application.service.MemberLevelService;
import com.todo.member.common.base.redis.MemberKeyBuild;
import com.todo.member.common.enums.LevelStatusEnum;
import com.todo.member.infrastructure.entity.condition.MemberLevelInfoCondition;
import com.todo.member.infrastructure.entity.po.MemberLevelInfoPO;
import com.todo.member.infrastructure.repository.MemberLevelInfoRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author azhebuxing
 * @date 2025/2/12 21:55
 * @description
 */
@Slf4j
@Service
public class MemberLevelServiceImpl implements MemberLevelService {

    public static final int MAX_LEVEL = 10;


    @Resource
    private MemberLevelInfoRepository memberLevelInfoRepository;
    @Resource
    private RedisService redisService;

    @Override
    public Boolean insertMemberLevel(MemberLevelBO memberLevelBO) {
        if (memberLevelBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (memberLevelBO.getLevel() > MAX_LEVEL) {
            log.error("MemberLevelService#insertMemberLevel 等级不能大于10 memberLevelBO:【{}】", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "等级不能大于10");
        }
        MemberLevelInfoPO alreadyData = memberLevelInfoRepository.queryMemberLevelByName(memberLevelBO.getLevelName());
        if (alreadyData != null) {
            log.error("MemberLevelService#insertMemberLevel 标题名称已存在 memberLevelBO:【{}】", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "标题名称已存在");
        }
        MemberLevelInfoPO memberLevelInfoPO = MemberInfoConvert.convertToMemberLevelInfoPO(memberLevelBO);
        Boolean inserted = memberLevelInfoRepository.insertMemberLevelInfoPO(memberLevelInfoPO);
        if (inserted) {
            String redisKey = MemberKeyBuild.buildMemberLevelKey(memberLevelBO.getId());
            redisService.set(redisKey, JSONObject.toJSONString(memberLevelBO));
        }
        return inserted;
    }

    @Override
    public Boolean updateMemberLevel(MemberLevelBO memberLevelBO) {
        if (memberLevelBO == null || memberLevelBO.getId() == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (memberLevelBO.getLevel() > MAX_LEVEL) {
            log.error("MemberLevelService#updateMemberLevel 等级不能大于10 memberLevelBO:【{}】", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "等级不能大于10");
        }
        MemberLevelBO alreadyData = queryMemberLevelById(memberLevelBO.getId());
        if (alreadyData == null) {
            log.error("MemberLevelService#updateMemberLevel 更新会员等级信息失败，当前数据已经不存在 memberLevelBO:{}", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST, "数据不存在");
        }
        if (alreadyData.getStatus().equals(LevelStatusEnum.RUNNING)) {
            log.error("MemberLevelService#updateMemberLevel 更新会员等级信息失败，当前数据状态禁止操作 memberLevelBO:{}", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.OPERATION_FAILED, "当前数据状态禁止操作");
        }
        if (!alreadyData.getLevelName().equals(memberLevelBO.getLevelName())) {
            MemberLevelInfoPO memberLevelInfoPO = memberLevelInfoRepository.queryMemberLevelByName(memberLevelBO.getLevelName());
            if (memberLevelInfoPO != null) {
                log.error("MemberLevelService#updateMemberLevel 更新会员等级信息失败，当前数据已经存在 memberLevelBO:{}", JSONObject.toJSONString(memberLevelBO));
                throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "标题名称已存在");
            }
        }
        MemberLevelInfoPO memberLevelInfoPO = MemberInfoConvert.convertToMemberLevelInfoPO(memberLevelBO);
        Boolean updated = memberLevelInfoRepository.updateMemberLevelInfoPOById(memberLevelInfoPO);
        if (updated) {
            String redisKey = MemberKeyBuild.buildMemberLevelKey(memberLevelBO.getId());
            redisService.del(redisKey);
        }
        return updated;
    }

    @Override
    public Boolean removeMemberLevelById(Long id) {
        if (id == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        MemberLevelBO memberLevelBO = queryMemberLevelById(id);
        if (memberLevelBO == null) {
            return true;
        }
        if (memberLevelBO.getStatus().equals(LevelStatusEnum.RUNNING)) {
            log.error("MemberLevelService#removeMemberLevelById 删除会员等级信息失败，当前数据状态禁止操作 memberLevelBO:{}", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.OPERATION_FAILED, "当前数据状态禁止操作");
        }
        Boolean updated = memberLevelInfoRepository.removeMemberLevelInfoPOById(id);
        if (updated) {
            String redisKey = MemberKeyBuild.buildMemberLevelKey(id);
            redisService.del(redisKey);
        }
        return updated;
    }

    @Override
    public MemberLevelBO queryMemberLevelById(Long id) {
        if (id == null) {
            return null;
        }
        String redisKey = MemberKeyBuild.buildMemberLevelKey(id);
        if (redisService.hasKey(redisKey)) {
            String cacheValue = redisService.get(redisKey);
            MemberLevelBO memberLevelBO = JSONObject.parseObject(cacheValue, MemberLevelBO.class);
            return memberLevelBO;
        }
        MemberLevelInfoPO memberLevelInfoPO = memberLevelInfoRepository.queryMemberLevelInfoPOById(id);
        if (memberLevelInfoPO != null) {
            MemberLevelBO memberLevelBO = MemberInfoConvert.convertToMemberLevelBO(memberLevelInfoPO);
            redisService.set(redisKey, JSONObject.toJSONString(memberLevelBO));
            return memberLevelBO;
        }
        return null;
    }

    @Override
    @Transactional
    public Boolean updateMemberLevelStatusById(Long id, LevelStatusEnum oldStatus, LevelStatusEnum newStatus) {
        if (id == null || oldStatus == null || newStatus == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (newStatus.equals(oldStatus)) {
            return true;
        }
        MemberLevelBO memberLevelBO = queryMemberLevelById(id);
        if (memberLevelBO == null) {
            log.error("MemberLevelService#updateMemberLevelStatusById 更新会员等级信息失败，当前数据已经不存在 memberLevelBO:{}", JSONObject.toJSONString(memberLevelBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST, "数据不存在");
        }
        if (newStatus.equals(memberLevelBO.getStatus())) {
            return true;
        }
        //如果新状态为running，需要将其他running的相同等级的状态调整
        if (newStatus.equals(LevelStatusEnum.RUNNING)) {
            List<MemberLevelBO> memberLevelBOS = queryEffectiveMemberLevelList();
            for (MemberLevelBO effectiveData : memberLevelBOS) {
                if (effectiveData.getLevel().equals(memberLevelBO.getLevel())) {
                    memberLevelInfoRepository.updateMemberLevelInfoStatusById(effectiveData.getId(), effectiveData.getStatus(), LevelStatusEnum.SHUTDOWN);
                    redisService.hDel(MemberKeyBuild.buildEffectiveMemberLevelListKey(), String.valueOf(effectiveData.getId()));
                }
            }
        }
        Boolean updated = memberLevelInfoRepository.updateMemberLevelInfoStatusById(id, oldStatus, newStatus);
        if (updated) {
            if (newStatus.equals(LevelStatusEnum.RUNNING)) {
                String redisKey = MemberKeyBuild.buildEffectiveMemberLevelListKey();
                redisService.hSet(redisKey, String.valueOf(id), JSONObject.toJSONString(memberLevelBO));
            }
            if (oldStatus.equals(LevelStatusEnum.RUNNING)) {
                String redisKey = MemberKeyBuild.buildEffectiveMemberLevelListKey();
                redisService.hDel(redisKey, String.valueOf(id));
            }
        }
        return null;
    }

    @Override
    public List<MemberLevelBO> queryEffectiveMemberLevelList() {
        String redisKey = MemberKeyBuild.buildEffectiveMemberLevelListKey();
        Map<String, String> stringStringMap = redisService.hGetAll(redisKey);
        if (MapUtils.isNotEmpty(stringStringMap)) {
            List<MemberLevelBO> memberLevelBOList = Lists.newArrayList();
            for (String key : stringStringMap.keySet()) {
                MemberLevelBO memberLevelBO = JSONObject.parseObject(stringStringMap.get(key), MemberLevelBO.class);
                memberLevelBOList.add(memberLevelBO);
            }
            //每个等级只能有一个
            Map<Integer, MemberLevelBO> collect = memberLevelBOList.stream().collect(Collectors.toMap(MemberLevelBO::getVersion, Function.identity(), (k1, k2) -> k1));
            return new ArrayList<>(collect.values());
        }
        return Collections.emptyList();
    }

    @Override
    public PageResult<MemberLevelBO> queryMemberLevelByPage(MemberLevelConditionBO memberLevelConditionBO) {
        if (memberLevelConditionBO == null){
            return PageResult.of(new ArrayList<>(), 0, 0, 0);
        }
        MemberLevelInfoCondition memberLevelInfoCondition = MemberInfoConvert.convertToMemberLevelInfoCondition(memberLevelConditionBO);
        PageResult<MemberLevelInfoPO> pageResult = memberLevelInfoRepository.queryMemberLevelInfoPOByPage(memberLevelInfoCondition);
        if (pageResult == null){
            return PageResult.of(new ArrayList<>(), memberLevelConditionBO.getPageNum(), memberLevelConditionBO.getPageSize(), 0);
        }
        return MemberInfoConvert.convertToMemberLevelBOPage(pageResult);
    }
}
